package raft

import (
	"fmt"
	"net/rpc"
	"strconv"
)

/*
 投票--不能通过this来获取到当前节点的raft数据
*/
func (this *Raft) VoteRpcCall(candidateVote CandidateVote, voteReplyPtr *VoteReply) error {
	fmt.Println("给" + strconv.Itoa(candidateVote.NodeId) + "投票")
	//重置定时器
	GlobalRaftPtr.resetTimerChn <- struct{}{}
	voteReplyPtr.NodeTerm = GlobalRaftPtr.Term
	if GlobalRaftPtr.Term > candidateVote.Term {
		//候选人的任期号小于当前节点任期号
		voteReplyPtr.Flag = false
	} else {
		//候选人的任期号大于当前节点任期号
		voteReplyPtr.Flag = true
		GlobalRaftPtr.Term = candidateVote.Term
		GlobalRaftPtr.state = STATE_FOLLOWER
		GlobalRaftPtr.isLeader = false
		GlobalRaftPtr.VotedFor = candidateVote.NodeId
	}
	fmt.Printf("给,%v,投票结果：%v\n", strconv.Itoa(candidateVote.NodeId), voteReplyPtr)
	return nil
}

/*
 心跳
*/
func (this *Raft) HeartbeatRpcCall(logReplicate LogReplicate, logReplicateReplyPtr *LogReplicateReply) error {
	//重置超时时间
	if len(logReplicate.LogSlc) > 0 {
		fmt.Printf("接收到leader:%v的心跳,参数：%v\n", logReplicate.LeaderNode.Addr, logReplicate)
	}
	GlobalRaftPtr.resetTimerChn <- struct{}{}
	GlobalRaftPtr.consistencyCheckDaemon(logReplicate, logReplicateReplyPtr)
	GlobalRaftPtr.appendLog(logReplicate, logReplicateReplyPtr)
	if GlobalRaftPtr.VotedFor != logReplicate.LeaderNode.Id {
		GlobalRaftPtr.VotedFor = logReplicate.LeaderNode.Id
	}
	return nil
}

//===============================日志相关的RPC函数===================================
/*
 日志复制
*/
func (this *Raft) AppendEntryRpcCall(logReplicate LogReplicate, logReplicateReplyPtr *LogReplicateReply) error {
	GlobalRaftPtr.consistencyCheckDaemon(logReplicate, logReplicateReplyPtr)
	GlobalRaftPtr.appendLog(logReplicate, logReplicateReplyPtr)
	return nil
}

/**
日志一致性检查
*/
func (this *Raft) ConsistencyCheckDaemonRpcCall(logReplicate LogReplicate, logReplicateReplyPtr *LogReplicateReply) error {
	GlobalRaftPtr.consistencyCheckDaemon(logReplicate, logReplicateReplyPtr)
	return nil
}

/*
  客户端添加数据
*/
func (this *Raft) AddDataRpcCall(cmdData string, leaderNodePtr *Node) error {
	fmt.Printf("当前接收到client日志的节点是：%v", GlobalRaftPtr)
	if GlobalRaftPtr.isLeader {
		//当前节点是Leader，直接追加数据
		logEntry := LogEntry{
			Term: GlobalRaftPtr.Term,
			Cmd:  cmdData,
		}
		GlobalRaftPtr.sendLogCopy(logEntry)
		leaderNodePtr.Id = GlobalRaftPtr.selfNode.Id
		leaderNodePtr.Addr = GlobalRaftPtr.selfNode.Addr
		return nil
	} else {
		//当前节点不是Leader，把数据转发给Leader并把Leader的地址发送给Client
		for _, node := range GlobalRaftPtr.allNodeSlc {
			if node.Id == GlobalRaftPtr.VotedFor {
				//Call(node,"Raft.CmdDirectRpcCall",cmdData,&struct{}{})
				fmt.Println("转发给Leader===》" + cmdData)
				leaderNodePtr.Id = node.Id
				leaderNodePtr.Addr = node.Addr
				break
			}
		}
		return nil
	}
}

/*
  follower转发消息给Leader
*/
func (this *Raft) CmdDirectRpcCall(data string, _ *struct{}) error {
	logEntry := LogEntry{
		Term: GlobalRaftPtr.Term,
		Cmd:  data,
	}
	GlobalRaftPtr.sendLogCopy(logEntry)
	return nil
}

/*
  获取Leader节点的地址
*/
func (this *Raft) GetLeaderNetAddrRpcCall(_ struct{}, leaderNodePtr *Node) error {
	leaderNodeId := GlobalRaftPtr.VotedFor
	leaderNodePtr.Id = -1
	leaderNodePtr.Addr = ""
	if leaderNodeId != -1 {
		for _, node := range GlobalRaftPtr.allNodeSlc {
			if node.Id == leaderNodeId {
				leaderNodePtr.Id = node.Id
				leaderNodePtr.Addr = node.Addr
				break
			}
		}
	}
	return nil
}

//=====================================远程调用工具函数==================================
/*
 远程调用
*/
func Call(remoteNode Node, methodName string, args interface{}, reply interface{}) {
	var callClient *rpc.Client
	var err error
	if NodeIdKeyConnMap[remoteNode.Id] == nil {
		NodeIdKeyConnMapLock.Lock()
		callClient, err = rpc.Dial("tcp", remoteNode.Addr)
		NodeIdKeyConnMap[remoteNode.Id] = callClient
		NodeIdKeyConnMapLock.Unlock()
		//fmt.Println("新建-"+remoteNode.Addr+"-conn连接")
	} else {
		callClient = NodeIdKeyConnMap[remoteNode.Id]
		//fmt.Println("从map缓存中获取conn连接")
	}
	if err != nil {
		fmt.Println("连接->" + remoteNode.Addr + "失败" + err.Error())
		deleteNode(remoteNode)
	} else {
		err = callClient.Call(methodName, args, reply)
		if err != nil {
			fmt.Println("远程调用" + remoteNode.Addr + ":" + methodName + "失败" + err.Error())
			deleteNode(remoteNode)
		}
	}
}

/*
 删除已经断连的节点
*/
func deleteNode(deleteNode Node) {
	delete(NodeIdKeyConnMap, deleteNode.Id)
	var deleteNodeIdx = -1
	for i, node := range GlobalRaftPtr.allNodeSlc {
		if node.Id == deleteNode.Id {
			deleteNodeIdx = i
			break
		}
	}
	if deleteNodeIdx != -1 {
		GlobalRaftPtr.allNodeSlc = append(GlobalRaftPtr.allNodeSlc[0:deleteNodeIdx], GlobalRaftPtr.allNodeSlc[deleteNodeIdx+1:]...)
	}
	fmt.Println("删除的节点：" + deleteNode.Addr)
	fmt.Println(GlobalRaftPtr.allNodeSlc)
}
